hvm: Fix destroy_periodic_time() to not race destruction of one-shot timers.
authorKeir Fraser <keir.fraser@citrix.com>
Wed, 12 Dec 2007 11:08:21 +0000 (11:08 +0000)
committerKeir Fraser <keir.fraser@citrix.com>
Wed, 12 Dec 2007 11:08:21 +0000 (11:08 +0000)
This bug was tracked down by Dexuan Cui <dexuan.cui@intel.com>

Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
xen/arch/x86/hvm/vioapic.c
xen/arch/x86/hvm/vlapic.c
xen/arch/x86/hvm/vpt.c
xen/include/asm-x86/hvm/vpt.h

index 670cdf5979ee33bab4c108833ff30220c3d54ef5..cfc80c5aa1ce6e324acbbdf872705b0a6bd25e69 100644 (file)
@@ -300,7 +300,7 @@ static uint32_t ioapic_get_delivery_bitmask(
 static inline int pit_channel0_enabled(void)
 {
     PITState *pit = &current->domain->arch.hvm_domain.pl_time.vpit;
-    return pit->pt0.enabled;
+    return pt_active(&pit->pt0);
 }
 
 static void vioapic_deliver(struct hvm_hw_vioapic *vioapic, int irq)
index 5ac455b1fe15a140918d1885726be3f78b75e0a4..2bf3745c8b2b5889788512ca37cd4ea275cbaa19 100644 (file)
@@ -977,15 +977,12 @@ void vlapic_destroy(struct vcpu *v)
 
 int is_lvtt(struct vcpu *v, int vector)
 {
-    return vcpu_vlapic(v)->pt.enabled &&
-           vector == vlapic_lvt_vector(vcpu_vlapic(v), APIC_LVTT);
+    return (pt_active(&vcpu_vlapic(v)->pt) &&
+            (vector == vlapic_lvt_vector(vcpu_vlapic(v), APIC_LVTT)));
 }
 
 int is_lvtt_enabled(struct vcpu *v)
 {
-    if ( unlikely(!vlapic_enabled(vcpu_vlapic(v))) ||
-            !vlapic_lvt_enabled(vcpu_vlapic(v), APIC_LVTT)) 
-        return 0;
-
-    return 1;
+    return (vlapic_enabled(vcpu_vlapic(v)) &&
+            vlapic_lvt_enabled(vcpu_vlapic(v), APIC_LVTT));
 }
index 0a780298b813c52fd538601232bf3278b1466324..d4bc8690c866205d22acdc3990554254e1f72c36 100644 (file)
@@ -225,8 +225,9 @@ void pt_intr_post(struct vcpu *v, struct hvm_intack intack)
 
     if ( pt->one_shot )
     {
-        pt->enabled = 0;
-        list_del(&pt->list);
+        if ( pt->on_list )
+            list_del(&pt->list);
+        pt->on_list = 0;
     }
     else
     {
@@ -294,7 +295,6 @@ void create_periodic_time(
 
     spin_lock(&v->arch.hvm_vcpu.tm_lock);
 
-    pt->enabled = 1;
     pt->pending_intr_nr = 0;
     pt->do_not_freeze = 0;
 
@@ -324,6 +324,7 @@ void create_periodic_time(
     pt->cb = cb;
     pt->priv = data;
 
+    pt->on_list = 1;
     list_add(&pt->list, &v->arch.hvm_vcpu.tm_list);
 
     init_timer(&pt->timer, pt_timer_fn, pt, v->processor);
@@ -334,12 +335,14 @@ void create_periodic_time(
 
 void destroy_periodic_time(struct periodic_time *pt)
 {
-    if ( !pt->enabled )
+    /* Was this structure previously initialised by create_periodic_time()? */
+    if ( pt->vcpu == NULL )
         return;
 
     pt_lock(pt);
-    pt->enabled = 0;
-    list_del(&pt->list);
+    if ( pt->on_list )
+        list_del(&pt->list);
+    pt->on_list = 0;
     pt_unlock(pt);
 
     /*
index 9f69024340d874eee6bce43b44a8e49f13291e37..0831d37dcc12a9b78bbd7f5f122e61e3d7698f9f 100644 (file)
@@ -72,12 +72,12 @@ typedef void time_cb(struct vcpu *v, void *opaque);
 
 struct periodic_time {
     struct list_head list;
-    char enabled;
-    char one_shot;              /* one shot time */
-    char do_not_freeze;
+    bool_t on_list;
+    bool_t one_shot;
+    bool_t do_not_freeze;
     u8 irq;
     struct vcpu *vcpu;          /* vcpu timer interrupt delivers to */
-    u32 pending_intr_nr;        /* the couner for pending timer interrupts */
+    u32 pending_intr_nr;        /* pending timer interrupts */
     u64 period;                 /* frequency in ns */
     u64 period_cycles;          /* frequency in cpu cycles */
     s_time_t scheduled;         /* scheduled timer interrupt */
@@ -140,6 +140,17 @@ void pt_update_irq(struct vcpu *v);
 void pt_intr_post(struct vcpu *v, struct hvm_intack intack);
 void pt_reset(struct vcpu *v);
 void pt_migrate(struct vcpu *v);
+
+/* Is given periodic timer active? */
+#define pt_active(pt) ((pt)->on_list)
+
+/*
+ * Create/destroy a periodic (or one-shot!) timer.
+ * The given periodic timer structure must be initialised with zero bytes or
+ * have been initialised by a previous invocation of create_periodic_time().
+ * Note that, for a given periodic timer, invocations of these functions MUST
+ * be serialised.
+ */
 void create_periodic_time(
     struct vcpu *v, struct periodic_time *pt, uint64_t period,
     uint8_t irq, char one_shot, time_cb *cb, void *data);